/* 拓扑排序
* 1.做法:
    (1) 合并两个集合
    (2) 查询某个元素的祖宗节点
    (3) 记录方法:
        记录每个集合大小: 绑定到根节点上
        记录每个点到根节点的距离: 绑定到每个元素上

* 2.离散化:
    (1) 保留排序: 排序，判重，二分
    (2) 不保留排序: map, hash

* 本题: 并查集
    用sum数组表示序列S的前缀和:
    1.S[L~R] 有偶数个1 -> sum[L-1]与sum[R]奇偶性相同
    2.S[L~R] 有奇数个1 -> sum[L-1]与sum[R]奇偶性不同
    
    如果当前加入的条件与它之前的状态相等即不矛盾，反之即为矛盾
*/

#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
#include <algorithm> 
#include <vector>
#include <unordered_map>
// #define ONLINE_GUDGE
using namespace std;
const int N = 2e4+10;

int n, m;
int fa[N], d[N]; // d[x]表示x与fa[x]的关系 0同类 1不同类
unordered_map<int, int> hsh;

inline int find(int x)
{
    if(fa[x] != x){
        int fx = find(fa[x]);
        d[x] ^= d[fa[x]]; // x所在列全部加上fa[x]的距离
        fa[x] = fx;
    }
    return fa[x];
}

inline int map(int x) {
    if (hsh.count(x)) {
        return hsh[x];
    }
    return hsh[x] = ++n;
}

int main()
{

    #ifdef ONLINE_JUDGE
    ios::sync_with_stdio(false);   
	cin.tie(0);
    #else
    freopen("./in.txt","r",stdin);
    #endif
    cin >> n >> m; n = 0;
    for(int i = 0; i< N; i++) fa[i] = i;
    
    int res = m; //如果无矛盾, 输出问题数量, 初始的时候为m
    for (int i = 1; i <= m; i++) {
        int l, r; string op; cin >> l >> r >> op;
        l = map(l-1); r = map(r);

        int t = 0;
        if(op == "odd") t = 1;
        int fl = find(l), fr = find(r);
        if(fl == fr){
            if((d[l]^d[r]) != t){
                res = i-1;
                break;
            }
        }
        else{
            fa[fl] = fr;
            d[fl] = d[l] ^ d[r] ^ t;
        }  
    }
    cout << res << endl;
    return 0;
}
